#pragma once
#include <BWAPI.h>
#include <BWTA.h>
#include <deque>

enum EFormations
{
	ZFNone = 0,
	ZFVLine,
	ZFHLine,
	ZFBackslash,
	ZFForeslash,
	ZFDoubleVLine,
	ZFDoubleVLineDense,
	ZFDoubleHLine,
	ZFDoubleHLineDense,
	ZFCross,
	ZFPlus,
	ZFBox,
	ZFBlock,
	ZFCircle,
	ZFDiamond,
};

class CFormation
{
public:
	typedef std::map<BWAPI::Unit*, CFormation*> TFormationPairs;
	typedef std::map<BWAPI::Unit*, int> TUnitMap;
private:
	static std::set<CFormation*> formations;
	static TFormationPairs formationPairs;
	TUnitMap units;
	std::deque<BWAPI::Position> waypoints;
	EFormations formation;
	BWAPI::Unit *target;

	bool reserved;

	int slotSize;

	CFormation(BWAPI::Position center, EFormations formation);

	void calcSlotSize();
public:
	~CFormation();

	void reserve();
	void release();

	void joinFormation(BWAPI::Unit* unit);
	void leaveFormation(BWAPI::Unit* unit);

	bool isWellFormed();
	bool isInPosition(BWAPI::Unit* unit);

	BWAPI::Position getPosition(int slot);
	BWAPI::Position getPosition(BWAPI::Unit* unit);
	int getDiameter();

	void recalculateSlots();

	int getUnitSlot(BWAPI::Unit* unit);
	TUnitMap getUnits();

	void setFormation(EFormations formation);
	BWAPI::Position getCenter();
	void setCenter(BWAPI::Position center);
	void addWayPoint(BWAPI::Position center);
	BWAPI::Unit* getTarget();
	void setTarget(BWAPI::Unit* target);

	void disbandFormation();
	CFormation* splitFormation();
	void mergeFormations(std::set<CFormation*> formations);

	static std::set<CFormation*> getFormations();
	static CFormation* getFormation(BWAPI::Unit* unit);

	static CFormation* getEmptyFormation(BWAPI::Position center = BWAPI::Positions::None, EFormations formation = ZFBox);

	static bool onSendText(std::string text);
};

void CalculateNearestSlots(CFormation::TUnitMap& units, std::map<int, BWAPI::Position> slots);
